// +---------------------------------------------------------------
// | 封装js - Math 应用
// +---------------------------------------------------------------
/**
 * 随机字符串
 * @param {Number} length 长度
 * @param {String} mode upper|lower
 * @returns {String}
 */
Math.nonceStr = function (length = 6, mode = "upper") {
    if (length <= 11) {
        return Math.random()
            .toString(36)
            .slice(2, 2 + length)
            .padEnd(length, "0")
            [mode === "upper" ? "toLocaleUpperCase" : "toLocaleLowerCase"]();
    } else {
        return this.nonceStr(11) + this.nonceStr(length - 11);
    }
};

/**
 * 随机颜色
 * @returns {String}
 */
Math.color = function () {
    return "#" + Math.random().toString(16).slice(2, 8).padEnd(6, "0");
};

// +---------------------------------------------------------------
// | 封装js - 字符串 应用
// +---------------------------------------------------------------

String.prototype.trim = function () {
    return this.replace(/(^\s*)|(\s*$)/g, "");
};

// +---------------------------------------------------------------
// | 封装js - request 请求
// +---------------------------------------------------------------

window.request = {
    qs: function (name) {
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.has(name)) {
            return urlParams.get(name);
        } else {
            const regex = new RegExp(`/${name}/([^/]+)`);
            const res = window.location.href.match(regex);
            return res ? res[1] : null;
        }
    },
    // 过滤对象中的值
    filter: function (object, haystack = [null, undefined, "", NaN]) {
        return Object.entries(object).reduce((result, [key, value]) => {
            if (!haystack.includes(value)) result[key] = value;
            return result;
        }, {});
    },
    paginate(curr, total, size = 10) {
        return new Paginate(curr, total, size).generate();
    },
    get: function (url, params, success, fail) {
        if (typeof params == "function") {
            success
                ? ((fail = success), (success = params))
                : (success = params),
                (params = undefined);
        }
        window.request.ajax("get", url, params, success, fail);
    },
    post: function (url, params, success, fail) {
        if (typeof params == "function") {
            success
                ? ((fail = success), (success = params))
                : (success = params),
                (params = undefined);
        }
        window.request.ajax("post", url, params, success, fail);
    },
    put: function (url, params, success, fail) {
        if (typeof params == "function") {
            success
                ? ((fail = success), (success = params))
                : (success = params),
                (params = undefined);
        }
        params["_method"] = "PUT";
        window.request.ajax("post", url, params, success, fail);
    },
    delete: function (url, params, success, fail) {
        if (typeof params == "function") {
            success
                ? ((fail = success), (success = params))
                : (success = params),
                (params = undefined);
        }
        params["_method"] = "DELETE";
        window.request.ajax("post", url, params, success, fail);
    },
    ajax: function (method, url, params, success, fail) {
        const options = {};
        options.type = method.toUpperCase();
        options.url =
            url.substring(0, 4) === "http" ? url : window.location.origin + url;
        options.data = params || {};
        if (params instanceof FormData) {
            options.contentType = false;
            options.processData = false;
        }
        options.dataType = "json"; /* xml|html|json|jsonp|text|script */
        options.success = success || window.request.success;
        options.error = fail || window.request.error;
        console.info(options);
        $.ajax(options);
    },
};

function Paginate(currPage, total, size = 10) {
    this.currPage = currPage;
    this.total = total;
    this.size = size;
}
Paginate.prototype.cache = new Map();
Paginate.prototype.getPage = function (lastPage) {
    const result = [];
    for (let i = 1; i <= lastPage; i++) {
        result.push(i);
    }
    return result;
};
Paginate.prototype.proxyPage = function () {
    const args = Array.prototype.join.call(arguments, "-");
    if (this.cache.has(args)) {
        return this.cache.get(args);
    }
    const result = this.getPage.apply(this, arguments);
    this.cache.set(args, result);
    return result;
};
Paginate.prototype.generate = function () {
    const lastPage = Math.ceil(this.total / this.size);
    const step = 5;
    const b = "...";
    const m = this.proxyPage(lastPage);

    let a = [];
    if (lastPage <= 8) {
        return m;
    } else if (this.currPage >= step && this.currPage <= lastPage - step + 1) {
        const i = m.indexOf(this.currPage - 2);
        a = m.slice(i, i + step);
        return [1, b, ...a, b, lastPage];
    } else if (this.currPage < step) {
        a = m.slice(0, step);
        return [...a, b, lastPage];
    } else if (this.currPage > lastPage - step) {
        return [1, b, ...m.slice(-5)];
    } else {
        const newPaginate = new Paginate(1, this.total, this.size);
        return newPaginate.generate();
    }
};

// +---------------------------------------------------------------
// | 扩展 Date 函数
// +---------------------------------------------------------------
/** 格式化时间：YYYY-mm-dd */
Date.prototype.toDate = function () {
    return new Date(this.getTime() + 8 * 3600 * 1000)
        .toISOString()
        .substring(0, 10);
};
/** 格式化时间：yyyy-MM-dd HH:ii:ss */
Date.prototype.toDateTime = function () {
    return new Date(this.getTime() + 8 * 3600 * 1000)
        .toJSON()
        .substring(0, 19)
        .replace("T", " ");
};
/** 在当前时间上加上时间戳：加上5分钟，timestamp=300 */
Date.prototype.plusTimes = function (timestamp) {
    return new Date(this.getTime() + timestamp * 1000);
};
/** 在当前时间上加某些天 */
Date.prototype.plusDays = function (days) {
    return new Date(this.getTime() + days * 86400 * 1000);
};

/**
 * 返回一个加上若干个月的新Date
 * 注1：Date(2-28).plusMonth(1)=Date(3-28)。如果需要变成3-31，需要另外的函数来处理。
 * 注2：Date(1-31).plusMonth(1)=Date(2-28)或Date(2-29)
 */
Date.prototype.plusMonths = function (number) {
    let t = new Date(this);
    t.setMonth(this.getMonth() + number); //setMonth()会自动除以12
    //注意：此时，月数可能会自动进位，比如：1-31加上number=1的情况，会变成3-3（非闰年）或3-2（闰年），即2-31自动转换为下个月的某一天。

    let currentMonth = this.getMonth() + this.getFullYear() * 12; //获得月的绝对值
    let diff = t.getMonth() + t.getFullYear() * 12 - currentMonth; // 计算新旧两个月绝对值的差

    if (diff != number) {
        // 如果月绝对值的差和加上的月数不一样，说明月进位了
        t.setDate(0); /** 上个月的最后一天 */
    }
    return t;
};

const Validator = function () {
    this.cache = [];
};
Validator.prototype.add = function (condition, msg) {
    function createRule(rule) {
        if (typeof rule === "function") {
            return rule;
        }
        return function () {
            return !!rule;
        };
    }
    this.cache.push({
        rule: createRule(condition),
        msg: msg,
    });
};
Validator.prototype.valid = function () {
    let result = true;
    for (let i = 0; i < this.cache.length; i++) {
        let rule = this.cache[i].rule;
        let msg = this.cache[i].msg;
        let valid = rule();
        console.log("valid: ", valid);
        if (!valid) {
            // result = false
            result = msg || this.cache[i].msg;
            break;
        }
    }
    return result;
};
